/*
 * OPIAM Suite
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package opiam.admin.faare.service.services.triggers;

import opiam.admin.faare.config.javabeans.JBTrigger;
import opiam.admin.faare.exception.ConfigurationException;
import opiam.admin.faare.exception.ServiceException;
import opiam.admin.faare.persistence.javabeans.JBTop;
import opiam.admin.faare.service.UserContext;

import org.apache.log4j.Logger;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;

import java.io.StringReader;
import java.io.StringWriter;

import java.util.Date;
import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;


/**
 * This class is a trigger which allows to automatically send mails.<br>
 * The trigger needs merely to be declared in triggers_conf.xml.
 *
 **/
public class MailSenderTrigger implements TriggerInterface
{
    /** Velocity macros file. */
    public static final String MAILSENDER_VELOCIMACRO_LIB = "/config/service/triggers/mailsender_macro.vm";

    /** Instance of logger. */
    private static Logger _logger = Logger.getLogger(MailSenderTrigger.class);

    /** Mail server address property. */
    public static final String PARAM_SMTP_HOST = "mail.smtp.host";

    /** Sender template property. */
    public static final String PARAM_SENDER_ADDRESS_TEMPLATE = "mail.smtp.sender.template";

    /** Recipient template property. */
    public static final String PARAM_RECIPIENT_ADDRESS_TEMPLATE = "mail.smtp.recipient.template";

    /** Subject template property. */
    public static final String PARAM_SUBJECT_TEMPLATE = "mail.smtp.subject.template";

    /** Body filename property. */
    public static final String PARAM_BODY_TEMPLATE_FILENAME = "mail.smtp.body.filename";

    /** Triggers parameters. */
    private Properties param;

    /** Sender template value. */
    private String senderAddressTemplate;

    /** Recipient template value. */
    private String recipientAddressTemplate;

    /** Subject template value. */
    private String subjectTemplate;

    /** Body filename template value. */
    private String bodyTemplateFilename;

    /** Velocity object. */
    private VelocityEngine velocityEngine;

    /** Body template. */
    private Template bodyTemplate;

    /**
     * Initialization metghod.<br>
     * Checks that trigger parameters are all set.
     * @param props Trigger properties.
     * @param directory Configuration directory if any.
     *
     * @see opiam.admin.faare.service.services.triggers.TriggerInterface#initialize(Properties)
     */
    @Override
	public void initialize(Properties props, String directory)
    {
        this.param = props;

        String location = "In " + props.getProperty("_TRIGGER_NAME") + " : ";

        if (props.getProperty(PARAM_SMTP_HOST) == null)
        {
            throw new ConfigurationException(location + PARAM_SMTP_HOST +
                " not found");
        }

        senderAddressTemplate = props.getProperty(PARAM_SENDER_ADDRESS_TEMPLATE);

        if (senderAddressTemplate == null)
        {
            throw new ConfigurationException(location +
                PARAM_SENDER_ADDRESS_TEMPLATE + " not found");
        }

        recipientAddressTemplate = props.getProperty(PARAM_RECIPIENT_ADDRESS_TEMPLATE);

        if (recipientAddressTemplate == null)
        {
            throw new ConfigurationException(location +
                PARAM_RECIPIENT_ADDRESS_TEMPLATE + " not found");
        }

        subjectTemplate = props.getProperty(PARAM_SUBJECT_TEMPLATE);

        if (subjectTemplate == null)
        {
            throw new ConfigurationException(location + PARAM_SUBJECT_TEMPLATE +
                " not found");
        }

        bodyTemplateFilename = props.getProperty(PARAM_BODY_TEMPLATE_FILENAME);

        if (bodyTemplateFilename == null)
        {
            throw new ConfigurationException(location +
                PARAM_BODY_TEMPLATE_FILENAME + " not found");
        }

        initializeVelocity(directory);
    }

    /**
     * Method which performs the trigger action.<br>
     * It sends a mail with configured parameters.
     *
     * @param jbTrigger Trigger descriptor.
     * @param entry Entry which is subject of the action launching the trigger.
     * @param userContext Connected user context.
     *
     * @throws ServiceException not thrown by this implementation.
     * @see opiam.admin.faare.service.services.triggers.TriggerInterface#execute(JBTop, UserContext)
     */
    @Override
	public void execute(JBTrigger jbTrigger, JBTop entry,
        UserContext userContext) throws ServiceException
    {
        _logger.debug("...start execute");

        String to = getRecipientInstance(entry, userContext);
        String from = getSenderInstance(entry, userContext);

        // get the default Session
        Session session = Session.getDefaultInstance(param, null);

        try
        {
            // create a message
            Message msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress(from));

            InternetAddress[] address = {new InternetAddress(to)};
            msg.setRecipients(Message.RecipientType.TO, address);
            msg.setSubject(getSubjectInstance(entry, userContext));
            msg.setSentDate(new Date());

            msg.setText(getBodyInstance(entry, userContext));

            Transport.send(msg);
        }
        catch (AddressException e)
        {
            e.printStackTrace();
        }
        catch (MessagingException e)
        {
            e.printStackTrace();
        }

        _logger.debug("...end execute");
    }

    /**
     * Instanciates subject value.
     *
     * @param entry Subject entry.
     * @param userContext Connected user context.
     *
     * @return Subject string.
     */
    private String getSubjectInstance(JBTop entry, UserContext userContext)
    {
        StringReader reader = new StringReader(subjectTemplate);
        VelocityContext context = new VelocityContext();

        context.put("entry", entry);
        context.put("param", param);

        StringWriter sw = new StringWriter();

        try
        {
            velocityEngine.evaluate(context, sw, "getSubjectInstance", reader);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return sw.toString();
    }

    /**
     * Instanciates sender value.
     *
     * @param entry Subject entry.
     * @param userContext Connected user context.
     *
     * @return Sender string.
     */
    private String getSenderInstance(JBTop entry, UserContext userContext)
    {
        StringReader reader = new StringReader(senderAddressTemplate);
        VelocityContext context = new VelocityContext();

        context.put("entry", entry);
        context.put("param", param);

        StringWriter sw = new StringWriter();

        try
        {
            velocityEngine.evaluate(context, sw, "getSenderInstance", reader);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return sw.toString();
    }

    /**
     * Instanciates recipient value.
     *
     * @param entry Subject entry.
     * @param userContext Connected user context.
     *
     * @return Recipient string.
     */
    private String getRecipientInstance(JBTop entry, UserContext userContext)
    {
        StringReader reader = new StringReader(recipientAddressTemplate);
        VelocityContext context = new VelocityContext();

        context.put("entry", entry);
        context.put("param", param);

        StringWriter sw = new StringWriter();

        try
        {
            velocityEngine.evaluate(context, sw, "getRecipientInstance", reader);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return sw.toString();
    }

    /**
     * Instanciates body value.
     *
     * @param entry Subject entry.
     * @param userContext Connected user context.
     *
     * @return Body string.
     */
    private String getBodyInstance(JBTop entry, UserContext userContext)
    {
        VelocityContext context = new VelocityContext();

        context.put("entry", entry);
        context.put("param", param);

        StringWriter sw = new StringWriter();

        try
        {
            bodyTemplate.merge(context, sw);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return sw.toString();
    }

    /**
     * Initializes the velocity object.
     *
     * @param directory Configuration directory if any.
     */
    private void initializeVelocity(String directory)
    {
        _logger.debug(
            "Hello from Log4jCategoryExample - ready to start velocity");

        /*
         *  now create a new VelocityEngine instance, and
         *  configure it to use the category
         */
        velocityEngine = new VelocityEngine();

        velocityEngine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
            "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");

        velocityEngine.setProperty("runtime.log.logsystem.log4j.category",
            MailSenderTrigger.class.getName());

        if (directory == null)
        {
            /*DW/2530*/
            /*BeginPatch*/
            String fulpat = MailSenderTrigger.class.getResource("/config/")
                                                   .toString() + "/..";
            int nbsub = 5;

            if (fulpat.substring(7, 9).equals(":/"))
            { /* this is Windows */
                nbsub = 6;
            }

            velocityEngine.setProperty("file.resource.loader.path",
                fulpat.substring(nbsub));

            /*
                        velocityEngine.setProperty("file.resource.loader.path",
                        MailSenderTrigger.class.getResource("/").toString().substring(6));
            */
            /*DW/2530*/
            /*EndPatch*/
        }
        else
        {
            velocityEngine.setProperty("file.resource.loader.path",
                directory.concat("/"));
        }

        velocityEngine.setProperty("velocimacro.library",
            MAILSENDER_VELOCIMACRO_LIB);

        try
        {
            velocityEngine.init();
            bodyTemplate = velocityEngine.getTemplate(bodyTemplateFilename);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        _logger.debug(
            "this should follow the initialization output from velocity");
    }
}
